In [138]:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from ipywidgets import interact ,FloatSlider,Dropdown,Select,ToggleButtons
1.定义三维模型数据生成函数¶
In [139]:
def sphere():
"generate the coordarate of a unit sphere"
u = np.linspace(-np.pi, np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = np.outer(np.cos(u), np.sin(v))
y = np.outer(np.sin(u), np.sin(v))
z = np.outer(np.ones(np.size(u)), np.cos(v))
return x,y,z
In [140]:
def cube():
dx,dy,dz=1,1,1
x_start,y_start,z_start=0,0,0
x=np.linspace( x_start-dx/2, x_start+dx/2,2)
y=np.linspace( y_start-dy/2,y_start+dy/2,2)
z=np.linspace( z_start-dz/2, z_start+dz/2,2)
#生成六个面的坐标数据
zx,zy=np.meshgrid(x,y)
xz,xy=np.meshgrid(z,y)
yz,yx=np.meshgrid(z,x)
planeD=np.array([[np.full_like(xz,x_start+dx/2),xy, xz],
[np.full_like(xz,x_start-dx/2),xy, xz],
[yx, np.full_like(yz,y_start+dy/2),yz],
[yx, np.full_like(yz,y_start-dy/2),yz],
[zx, zy, np.full_like(zx,z_start+dz/2)],
[zx, zy, np.full_like(zx,z_start-dz/2)]])
return planeD
In [141]:
def parabolic_cylinder():
"""柱形抛面"""
x=np.linspace(-1,1,100)
y=np.linspace(-1,1,100)
xx,yy=np.meshgrid(x,y)
zz=xx**2
return xx,yy,zz
In [142]:
def parabolic():
"""抛物面"""
x=np.linspace(-1,1,100)
y=np.linspace(-1,1,100)
xx,yy=np.meshgrid(x,y)
zz=np.sqrt(xx**2+yy**2)
return xx,yy,zz
2.定义变换矩阵生成函数¶
In [143]:
def MatrixGenerator(x,y,z,theta_x, theta_y, theta_z):
"description:"
"create a matrix using to rotate and strech"
"Parameter"
"x,y,z:how many times strech along the initial x , y,z axis"
"theta_x, theta_y, theta_z:the angle rotated around x ,y ,z axis"
theta = np.array([theta_x, theta_y, theta_z])
Sigma = np.diag([x, y, z]) # scale x, then y, then z
# Rotation about x axis
Rx = np.array([[1, 0, 0],
[0, np.cos(theta[0]), -np.sin(theta[0])],
[0, np.sin(theta[0]), np.cos(theta[0])]])
# Rotation about y axis
Ry = np.array([[np.cos(theta[1]), 0, np.sin(theta[1])],
[0, 1, 0],
[-np.sin(theta[1]), 0, np.cos(theta[1])]])
# Rotation about z axis
Rz = np.array([[np.cos(theta[2]), -np.sin(theta[2]), 0],
[np.sin(theta[2]), np.cos(theta[2]), 0],
[0, 0, 1]])
# Rotate and scal
return Rz @ Ry @ Rx @ Sigma
3. 定义变换矩阵作用在三维模型数据算法函数¶
In [172]:
def rot(xx,yy,zz,A):
"""
description:
使用矩阵A对三维坐标xx,yy,zz进行变换
parameter:
xx,yy,zz :模型的x y z三维坐标
A:对模型进行线性变换的矩阵
"""
xR = np.zeros_like(xx)
yR = np.zeros_like(yy)
zR = np.zeros_like(zz)
for i in range(xx.shape[0]):
for j in range(xx.shape[1]):
vec = [xx[i,j], yy[i,j], zz[i,j]]
vecR = A @ vec
xR[i,j] = vecR[0]
yR[i,j] = vecR[1]
zR[i,j] = vecR[2]
return xR,yR,zR
4.将以上三个函数组合起来构建最终的变换函数¶
In [173]:
def transform(shape,xs,ys,zs,theta_x, theta_y, theta_z):
# Plot the module
fig = plt.figure()
ax1 = fig.add_subplot(121, projection='3d')
ax2 = fig.add_subplot(122, projection='3d')
X=MatrixGenerator(xs,ys,zs,theta_x, theta_y, theta_z)
if shape==cube:
planeD=cube()
for i in range(6):
surf1xu = ax1.plot_surface(planeD[i,0],planeD[i,1],planeD[i,2])
surf1xu.set_edgecolor('k')
ax1.set_xlim3d(-2, 2)
ax1.set_ylim3d(-2, 2)
ax1.set_zlim3d(-2,2)
ax1.set(xlabel="x",ylabel="y",zlabel="z",title="原始三维模型")
for i in range(6):
xR,yR,zR=rot(planeD[i,0],planeD[i,1,],planeD[i,2],X)
surf2xu = ax2.plot_surface(xR, yR, zR)
surf2xu.set_edgecolor('k')
ax2.set_xlim3d(-2, 2)
ax2.set_ylim3d(-2, 2)
ax2.set_zlim3d(-2,2)
ax2.set(xlabel="x",ylabel="y",zlabel="z",title="变换后三维模型")
else:
x ,y ,z=shape()
surf1 = ax1.plot_surface(x, y, z, cmap='jet',alpha=0.6,facecolors=plt.cm.jet(z),linewidth=0.5,rcount=30,ccount=30)
surf1.set_edgecolor('k')
ax1.set_xlim3d(-2, 2)
ax1.set_ylim3d(-2, 2)
ax1.set_zlim3d(-2, 2)
# plot the tranformed module
xR,yR,zR=rot(x,y,z,X)
ax2 = fig.add_subplot(122, projection='3d')
surf2 = ax2.plot_surface(xR, yR, zR,cmap='jet',alpha=0.6,linewidth=0.5,facecolors=plt.cm.jet(z),rcount=30,ccount=30)
surf2.set_edgecolor('k')
ax2.set_xlim3d(-2, 2)
ax2.set_ylim3d(-2, 2)
ax2.set_zlim3d(-2,2)
5.矩阵对三维模型变换的交互实现¶
In [174]:
%matplotlib inline
plt.rcParams['figure.figsize'] = [10, 5]
plt.rcParams.update({'font.size': 18})
interact(transform,shape=ToggleButtons(options=[('sphere',sphere), ('cube',cube),('parabolic',parabolic),('parabolic_cylinder',parabolic_cylinder)],value=sphere,description='3D module',disabled=False,),
xs=FloatSlider(min=0,max=2,step=0.1,value=1,description='x方向伸缩',continuous_update=False),
ys=FloatSlider(min=0,max=2,step=0.1,value=1,description='y方向伸缩',continuous_update=False),
zs=FloatSlider(min=0,max=2,step=0.1,value=1,description='z方向伸缩',continuous_update=False),
theta_x=FloatSlider(min=0,max=2*np.pi,step=0.1,value=1,description='绕x轴旋转',continuous_update=False),
theta_y=FloatSlider(min=0,max=2*np.pi,step=0.1,value=1,description='绕y轴旋转',continuous_update=False),
theta_z=FloatSlider(min=0,max=2*np.pi,step=0.1,value=1,description='绕z轴旋转',continuous_update=False))
interactive(children=(ToggleButtons(description='3D module', options=(('sphere', <function sphere at 0x0000022…
Out[174]:
<function __main__.transform(shape, xs, ys, zs, theta_x, theta_y, theta_z)>
In [ ]: